package qj.util.swing;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import qj.util.SwingUtil;
import qj.util.funct.F1;
import qj.util.funct.Fs;
import qj.util.funct.P0;
import qj.util.funct.P1;

public class JListLink<A> {
    private JList jList;
    private List<A> list;
    private F1<A, String> presentation;
    ArrayList<P1<A>> onSelects = new ArrayList<P1<A>>();
    ArrayList<P1<A>> onUiRemoves = new ArrayList<P1<A>>();

    public P0 refresh = new P0() {
        public void e() {
            final DefaultListModel listModel = (DefaultListModel) jList.getModel();
            listModel.removeAllElements();
            for (A a : list) {
                listModel.addElement(presentation.e(a));
            }
        }
    };

    public P1<A> refreshItem = new P1<A>() {
        public void e(A a) {
            int i = list.indexOf(a);
            final DefaultListModel listModel = (DefaultListModel) jList.getModel();
            listModel.setElementAt(presentation.e(a), i);
        }
    };

    public JListLink() {
        this(new F1<A, String>() {
            public String e(A obj) {
                return obj.toString();
            }
        });
    }

    public JListLink(F1<A, String> presentation) {

        final JList jList = new JList(new DefaultListModel());
        jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
        this.jList = jList;
        this.list = new ArrayList<A>();
        this.presentation = presentation;

        SwingUtil.onRemove(jList, new P1<Integer>() {
            public void e(Integer index) {
                if (index > -1) {
                    A a = JListLink.this.list.remove(index.intValue());
                    Fs.invoke(onUiRemoves, a);
                }
            }
        });

        jList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    int selectedIndex = jList.getSelectedIndex();
                    if (selectedIndex > -1) {
                        A a = list.get(selectedIndex);
                        Fs.invoke(onSelects, a);
                    }
                }
            }
        });
    }

    public void onSelect(P1<A> onSelect) {
        onSelects.add(onSelect);
    }
    public void onUiRemove(P1<A> onRemove) {
        onUiRemoves.add(onRemove);
    }

    public synchronized void add(A a) {
        list.add(a);
        final DefaultListModel listModel = (DefaultListModel) jList.getModel();
        listModel.addElement(presentation.e(a));
    }
    public void addSort(A a, Comparator<A> comparator) {
        int index = -Collections.binarySearch(list, a, comparator) - 1;
//        if (index > -1) {
            list.add(index, a);
            final DefaultListModel listModel = (DefaultListModel) jList.getModel();
            listModel.insertElementAt(presentation.e(a), index);
//        } else {
//            add(a);
//        }
    }

    public A getSelected() {
        int index = jList.getSelectedIndex();
        if (index > -1) {
            return list.get(index);
        } else {
            return null;
        }
    }

    public JList getComp() {
        return jList;
    }

    public List<A> getList() {
        return list;
    }

    public void select(A a) {
		jList.setSelectedIndex(list.indexOf(a));
	}

    public P1<A> remove = new P1<A>() {
        public void e(A obj) {
//            System.out.println("Remove " + obj);
            remove(obj);
        }
    };

    public synchronized void remove(A str) {
        int index = list.indexOf(str);
        if (index > -1) {
            list.remove(index);
            ((DefaultListModel)jList.getModel()).remove(index);
        }
    }
}
